/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    pmu.c
 *  @brief   PMU driver
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  gonght
 ****************************************************************/

#include "pmu.h"
#include "irq.h"

static PMU_CALLBACK pvd_rise_callback;
static PMU_CALLBACK pvd_fall_callback;

void pmu_aon_pvd_int_unmask(uint32_t bit_mask)
{
	uint32_t int_mask = 0;

	int_mask = readl(PMU_AON_IMC_REG);
	int_mask |= bit_mask;
	writel(int_mask, PMU_AON_IMC_REG);
}

void pmu_aon_pvd_int_mask(uint32_t bit_mask)
{
	uint32_t int_mask = 0;

	int_mask = readl(PMU_AON_IMC_REG);
	int_mask &= ~bit_mask;
	writel(int_mask, PMU_AON_IMC_REG);
}

uint32_t pmu_aon_get_pvd_int_status(void)
{
	return readl(PMU_AON_MIS_REG);
}

void pmu_aon_clear_pvd_int_status(uint32_t bit_mask)
{
	writel(bit_mask, PMU_AON_ICR_REG);
}

void pmu_aon_register_callback(PMU_CALLBACK pwron_cb, PMU_CALLBACK pwroff_cb)
{
	if (NULL != pwron_cb)
		pvd_rise_callback = pwron_cb;

	if (NULL != pwroff_cb)
		pvd_fall_callback = pwroff_cb;
}

void pmu_aon_power_domain_off(void)
{
	writel(0x1, PMU_AON_SLEEP_P_REG);
}

void pmu_aon_enter_battery_mode(void)
{
	writel(0x1, PMU_AON_BAT_MODE_REG);
}

void pmu_aon_triming_sel(enum triming_sel sel)
{
	writel(sel, PMU_AON_BAT_MODE_REG);
}

void pmu_active_pvd_lv_cfg(uint32_t lv)
{
	writel(lv, PMU_ACTIVE_PVD_LV_REG);
}

void pmu_active_triming_sel(enum triming_sel sel)
{
	writel(sel, PMU_ACTIVE_TRIMING_SEL_REG);
}

static void pmu_isr(void *args)
{
	uint32_t status = 0;

	status = pmu_aon_get_pvd_int_status();

	if ((BIT(PMU_AON_PVD_FALL_INT_POS) & status)
		&& (NULL != pvd_fall_callback)) {
		pmu_aon_clear_pvd_int_status(BIT(PMU_AON_PVD_FALL_INT_POS));
		pvd_fall_callback(args);
		pmu_aon_enter_battery_mode();
	}

	if ((BIT(PMU_AON_PVD_RISE_INT_POS) & status)
		&& (NULL != pvd_rise_callback)) {
		pmu_aon_clear_pvd_int_status(BIT(PMU_AON_PVD_RISE_INT_POS));
		pvd_rise_callback(args);
	}
}

void pmu_init(void)
{
	pmu_aon_pvd_int_unmask(BIT(PMU_AON_PVD_FALL_INT_POS) | BIT(PMU_AON_PVD_RISE_INT_POS));
	irq_disable(INT_PVT_FALL);
	irq_attach(INT_PVT_FALL, pmu_isr, NULL);
	irq_cfg_attr(INT_PVT_FALL, IRQ_ATTR_LEVEL);
	irq_enable(INT_PVT_FALL);
}
